#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#include "user.h"
#include "input_type.h"
#include "core.h"
#include "debug.h"

static int is_account_exist(char *name);
static int is_user_exist(struct login_info *p_login_info);

int user_register(struct login_info * p_login_info)
{
    FILE *fp_login_info = NULL;
    char *data;
    int ret = 0;
    int data_length = 0;
    struct login_info encipher_data;

    if (!p_login_info) {
        DEBUG("PARAM ERROR!\n");
        return 1;
    }

    /* 判断账号格式 */
    ret = get_num_char(p_login_info->name);
    if (ret == FALSE) {
        printf("账号格式错误，由大小写字母或数字组成！\n");
        return FALSE;
    }

    /*判断账号是否存在*/
    ret = is_account_exist(p_login_info->name);
    if (ret == TRUE) {
        printf("账号已经存在！\n");
        return FALSE;
    }

    /* 判断密码格式 */
    ret = get_num_char(p_login_info->password);
    if (ret == FALSE) {
        printf("密码格式错误，由大小写字母或数字组成！\n");
        return FALSE;
    }

    /*保存用户的昵称、账号、密码*/
    fp_login_info = fopen(USER_INFO_FILE, "ab+");
    if (!fp_login_info) {
        DEBUG("文件打开失败\n");
        return FALSE;
    }

    file_lock_set(fp_login_info, F_WRLCK);
    /*将要写入文件的内容加密*/
    memcpy(&encipher_data, p_login_info, sizeof(struct login_info));
    data = (char *)&encipher_data;
    data_length = sizeof(struct login_info);
    ret = en_incipher(data, data_length);
    if (ret < 0) {
        DEBUG("用户信息加密失败\n");
        return FALSE;
    }

    if (fwrite(&encipher_data, sizeof(struct login_info), 1, fp_login_info) != 1) {
        DEBUG("fwrite 用户信息 error");
        return FALSE;
    }

    file_lock_set(fp_login_info, F_UNLCK);
    fclose(fp_login_info);
    p_login_info->is_login = 1;
    printf("注册成功\n");

    return TRUE;
}

int user_login(struct login_info * p_login_info)
{
    FILE *fp_login_info = NULL;
    char *data;
    int ret = 0;
    int data_length = 0;
    struct login_info encipher_data;

    if (!p_login_info) {
        DEBUG("PARAM ERROR!\n");
        return 1;
    }

    /* 判断账号格式 */
    ret = get_num_char(p_login_info->name);
    if (ret == FALSE) {
        printf("账号格式错误，由大小写字母或数字组成！\n");
        return FALSE;
    }

    /*判断账号是否存在*/
    ret = is_account_exist(p_login_info->name);
    if (ret == FALSE) {
        printf("账号不存在！\n");
        return FALSE;
    }

    /* 判断密码格式 */
    ret = get_num_char(p_login_info->password);
    if (ret == FALSE) {
        printf("密码格式错误，由大小写字母或数字组成！\n");
        return FALSE;
    }
    /*判断密码是否正确*/
    ret = is_user_exist(p_login_info);
    if (ret == FALSE) {
        printf("密码错误！\n");
        return FALSE;
    }

    fp_login_info = fopen(USER_INFO_FILE, "ab+");
    if (!fp_login_info) {
        DEBUG("文件打开失败\n");
        return FALSE;
    }

    file_lock_set(fp_login_info, F_WRLCK);
    while (!feof(fp_login_info)) {
        if (fread(&login_info_data, sizeof(struct login_info), 1, fp_login_info)) {

            /*将从文件中读取的内容解密*/
            data = (char *)&login_info_data;
            data_length = sizeof(struct login_info);
            ret = encipher_or_decipher(data, data_length);
            if (ret < 0) {
                DEBUG("信息解密失败\n");
                return -1;
            }

            if ((!strcmp(login_info_data.name, p_login_info->name)) &&
                (!strcmp(login_info_data.password, p_login_info->password))) {
                strcpy(p_login_info->name, login_info_data.name);
                file_lock_set(fp_login_info, F_UNLCK);
                fclose(fp_login_info);
                break;
            }
        }
    }

    p_login_info->is_login = 1;
    printf("登录成功!欢迎%s!!!\n", p_login_info->name);    
    
    return TRUE;
}

int user_logout(struct login_info * p_login_info)
{
    if (!p_login_info) {
        DEBUG("PARAM ERROR!\n");
        return -1;
    }

    if(p_login_info->is_login != 1)
        return FALSE;

    p_login_info->is_login = 0;
    memset(p_login_info->name, '\0', USER_NAME_LENGTH);
    memset(p_login_info->password, '\0', USER_PASSWORD_LENGTH);

    return TRUE;
}

/**
 * @brief   判断账号是否存在
 * @param   account：装有账号的字符串指针
 * @return  错误返回-1 失败返回FALSE 成功返回TRUE
 */
int is_account_exist(char *name)
{
    FILE *fp_login_info = NULL;
    struct login_info login_info_data;
    char *data;
    int data_length, ret;

    if (!name) {
        DEBUG("PARAM ERROR!\n");
        return -1;
    }

    fp_login_info = fopen(USER_INFO_FILE, "ab+");
    if (!fp_login_info) {
        DEBUG("文件打开失败\n");
        return -1;
    }

    file_lock_set(fp_login_info, F_WRLCK);

    while (!feof(fp_login_info)) {
        if (fread(&login_info_data, sizeof(struct login_info), 1, fp_login_info)) {

            /*将从文件中读取的内容解密*/
            data = (char *)&login_info_data;
            data_length = sizeof(struct login_info);
            ret = en_incipher(data, data_length);
            if (ret < 0) {
                DEBUG("信息解密失败\n");
                return -1;
            }

            if (!strcmp(login_info_data.name, name))
                return TRUE;
        }
    }

    file_lock_set(fp_login_info, F_UNLCK);
    fclose(fp_login_info);

    return FALSE;
}

/**
 * @brief   判断用户是否存在
 * @param   p_login_info：装有用户信息的结构体指针
 * @return  错误返回-1 失败返回FALSE 成功返回TRUE
 */
int is_user_exist(struct login_info *p_login_info)
{
    FILE *fp_login_info = NULL;
    struct login_info login_info_data;
    char *data;
    int data_length, ret;

    if (!p_login_info) {
        DEBUG("PARAM ERROR!\n");
        return -1;
    }

    fp_login_info = fopen(USER_INFO_FILE, "ab+");
    if (!fp_login_info) {
        DEBUG("文件打开失败\n");
        return -1;
    }
    file_lock_set(fp_login_info, F_WRLCK);

    while (!feof(fp_login_info)) {

        if (fread(&login_info_data, sizeof(struct login_info), 1, fp_login_info)) {

            /*将从文件中读取的内容解密*/
            data = (char *)&login_info_data;
            data_length = sizeof(struct login_info);
            ret = en_incipher(data, data_length);
            if (ret < 0) {
                DEBUG("信息解密失败\n");
                return -1;
            }

            if ((!strcmp(login_info_data.name, p_login_info->name)) &&
                (!strcmp(login_info_data.password, p_login_info->password))) {
                file_lock_set(fp_login_info, F_UNLCK);
                fclose(fp_login_info);
                return TRUE;
            }
        }
    }

    file_lock_set(fp_login_info, F_UNLCK);
    fclose(fp_login_info);

    return FALSE;
}